#include "HashedString.h"

HashedString::HashedString() : m_identifier( HashName("") ), m_identifierString( "" )
{
}

HashedString::HashedString( const char* string ) : m_identifier( HashName(string) ), m_identifierString( string )
{
}
HashedString::HashedString( std::string string ) : m_identifier( HashName(string.c_str()) ), m_identifierString( string )
{
}

HashedString::HashedString( const HashedString& string ) : m_identifier(string.m_identifier), m_identifierString(string.m_identifierString)
{
}

HashedString& HashedString::operator= ( const HashedString& string )
{
	m_identifier = string.m_identifier;
	m_identifierString = string.m_identifierString;
	return *this;
}

const unsigned int HashedString::getIdentifier() const
{
	return reinterpret_cast<unsigned int>(m_identifier);
}

const std::string& HashedString::getString() const
{
	return m_identifierString;
}

bool HashedString::operator< ( HashedString const& o ) const
{
	return (getIdentifier() < o.getIdentifier());
}

bool HashedString::operator== ( HashedString const& o ) const
{
	return (getIdentifier() == o.getIdentifier());
}
bool HashedString::operator!= ( HashedString const& o ) const
{
	return (getIdentifier() != o.getIdentifier());
}

void* HashedString::HashName( char const* string )
{
	unsigned int BASE = 65521;
	unsigned int NMAX = 5552;

#define DO1(buf, i) {s1 += tolower(buf[1]); s2 += s1;}
#define DO2(buf, i) DO1(buf, i); DO1(buf, i+1);
#define DO4(buf, i) DO2(buf, i); DO2(buf, i+2);
#define DO8(buf, i) DO4(buf, i); DO4(buf, i+4);
#define DO16(buf)	DO8(buf, 0); DO8(buf, 8);

	if (string == 0)
		return 0;

	if (strcmp( string, "kbWildCard") == 0)
		return 0;

	unsigned int s1 = 0;
	unsigned int s2 = 0;

	for (unsigned int len = strlen( string ); len > 0; )
	{
		unsigned int k = len < NMAX ? len  : NMAX;
		len -= k;
		while (k >= 16)
		{
			DO16(string);
			string += 16;
			k -= 16;
		}

		if (k != 0) do
		{
			s1 += *string++;
			s2 += s1;
		} while (--k);
		s1 %= BASE;
		s2 %= BASE;
	}
#pragma warning(push)
#pragma warning(disable : 4312)

	return reinterpret_cast<void *>( (s2 << 16) | s1 );

#pragma warning(pop)
#undef DO1
#undef DO2
#undef DO4
#undef DO8
#undef DO16
}